package com.atguigu.file_slice.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

/**
 * <P> @Author: SongKeCheng
 * <P> Type: Class
 * <P> Description:
 * <P> Date: 2022/12/1:10:52
 */

@SuppressWarnings({"unchecked", ""})
public class FileSliceUtils {
    private static final Logger logger = LoggerFactory.getLogger(FileSliceUtils.class);

    public static void getSplitFile(String file, int count) {
        //预分配文件所占用的磁盘空间，在磁盘创建一个指定大小的文件，“r”表示只读，“rw”支持随机读写
        try {
            RandomAccessFile raf = new RandomAccessFile(new File(file), "r");
            //计算文件大小
            long length = raf.length();
            System.out.println(length);
            //计算文件切片后每一份文件的大小
            long maxSize = length / count;

            System.out.println(maxSize);
            //定义初始文件的偏移量(读取进度)
            long offset = 0L;
            //开始切割文件
            //count-1最后一份文件不处理
            for (int i = 0; i < count - 1; i++) {

                //标记初始化
                long fbegin = offset;
                //分割第几份文件
                long fend = (i + 1) * maxSize;
                //写入文件
                offset = getWrite(file, i, fbegin, fend);
            }
            //剩余部分文件写入到最后一份(如果不能平平均分配的时候)
            if (length - offset > 0) {
                //写入文件
                getWrite(file, count - 1, offset, length);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 指定文件每一份的边界，写入不同文件中
     *
     * @param file  源文件
     * @param index 源文件的顺序标识
     * @param begin 开始指针的位置
     * @param end   结束指针的位置
     * @return long
     */
    public static long getWrite(String file, int index, long begin, long end) {
        long endPointer = 0L;

        try (//申明文件切割后的文件磁盘
             RandomAccessFile in = new RandomAccessFile(new File(file), "r");
             //定义一个可读，可写的文件并且后缀名为.tmp的二进制文件
             RandomAccessFile out = new RandomAccessFile(new File(file + "_" + index + ".tmp"), "rw");) {

            //申明具体每一文件的字节数组
            byte[] b = new byte[1024];
            int n = 0;
            //从指定位置读取文件字节流
            in.seek(begin);
            //判断文件流读取的边界
            while (in.getFilePointer() <= end && (n = in.read(b)) != -1) {
                //从指定每一份文件的范围，写入不同的文件
                out.write(b, 0, n);
            }
            //定义当前读取文件的指针
            endPointer = in.getFilePointer();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return endPointer;
    }

    /**
     * 文件合并
     *
     * @param file      指定合并文件后的名称和路径
     * @param tempFile  分割前的文件名 这里需要指定之前的名称 然后进行拼接读取
     * @param tempCount 文件个数
     */
    public static void merge(String file, String tempFile, int tempCount) {
        try (RandomAccessFile raf = new RandomAccessFile(new File(file), "rw");) {
            //申明随机读取文件RandomAccessFile
            //开始合并文件，对应切片的二进制文件
            for (int i = 0; i < tempCount; i++) {
                //读取切片文件
                RandomAccessFile reader = new RandomAccessFile(new File(tempFile + "_" + i + ".tmp"), "r");
                byte[] b = new byte[1024];
                int n = 0;
                while ((n = reader.read(b)) != -1) {
                    //一边读，一边写
                    raf.write(b, 0, n);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
//        String file = "C:\\Users\\admin\\Desktop\\任务\\类网盘测试文件夹\\文件切片\\分布式技术图谱-sping_cloud、spring_cloud_alibab、dubbo.png";
        int count = 5;
        //1.根据现有的文件编写文件编写文件切片工具类
        //2.写入到二进制临时文件
//          getSplitFile(file, count);
        //3.根据实际的需求合并指定数量的文件
        String tempFile = "C:\\Users\\admin\\Desktop\\任务\\类网盘测试文件夹\\文件切片\\分布式技术图谱-sping_cloud、spring_cloud_alibab、dubbo.png";
        String file = "C:\\Users\\admin\\Desktop\\任务\\类网盘测试文件夹\\文件切片\\恢复\\img.jpg";
        merge(file, tempFile, 5);
    }

}
